﻿using System.ComponentModel;
using System.Timers;
using Asistente.Model.IFPUG;
using Asistente.Model.Representation;
using Asistente.Serialization;
using Asistente.Model.General;
using System;
using System.Collections.Generic;

namespace Asistente
{
    public class ViewModel: INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
 
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }
        #endregion     
        
        private Timer time;
        public Timer Time{ get { return time; } set { time = value; NotifyPropertyChanged("Time"); } } 

        private Int32 seconds;
        public Int32 Seconds { get { return seconds; } set { seconds = value; NotifyPropertyChanged("Seconds"); } }
        private Int32 minutes;
        public Int32 Minutes { get { return minutes; } set { minutes = value; NotifyPropertyChanged("Minutes"); } }
        private int hour;
        public int Hour { get { return hour; } set { hour = value; NotifyPropertyChanged("Hour"); } }
        public bool Playing { get; set; }

        public Application app;
        public Application App { get { return app; } set { app = value; NotifyPropertyChanged("App"); } }
        private UseCase selectedUseCase;
        public UseCase SelectedUseCase { get { return selectedUseCase; } set { selectedUseCase = value; NotifyPropertyChanged("SelectedUseCase"); } }
        private Screen selectedScreen;
        public Screen SelectedScreen { get { return selectedScreen; } set { selectedScreen = value; NotifyPropertyChanged("SelectedScreen"); } }
        private EditablePanel selectedEditablePanel;
        public EditablePanel SelectedEditablePanel { get { return selectedEditablePanel; } set { selectedEditablePanel = value; NotifyPropertyChanged("SelectedEditablePanel"); } }
        private ReadOnlyPanel selectedReadOnlyPanel;
        public ReadOnlyPanel SelectedReadOnlyPanel { get { return selectedReadOnlyPanel; } set { selectedReadOnlyPanel = value; NotifyPropertyChanged("SelectedReadOnlyPanel"); } }
        private Graph selectedGraph;
        public Graph SelectedGraph { get { return selectedGraph; } set { selectedGraph = value; NotifyPropertyChanged("SelectedGraph"); } }
        private Entity selectedEntity;
        public Entity SelectedEntity { get { return selectedEntity; } set { selectedEntity = value; NotifyPropertyChanged("SelectedEntity"); } }
        private MasterDetail selectedMasterDetail;
        public MasterDetail SelectedMasterDetail { get { return selectedMasterDetail; } set { selectedMasterDetail = value; NotifyPropertyChanged("SelectedMasterDetail"); } }
        private Control selectedControl;
        public Control SelectedControl { get { return selectedControl; } set { selectedControl = value; NotifyPropertyChanged("SelectedControl"); } }        
        private bool tabHeaderVisible; // Por defecto se inicializa en false
        public bool TabHeaderVisible {  get { return tabHeaderVisible; }  set { tabHeaderVisible = value; NotifyPropertyChanged("TabHeaderVisible"); } }

        public IMeasurable ifpugRepresentation;
        public IMeasurable IfpugRepresentation
        {
            get { return ifpugRepresentation; }
            set { ifpugRepresentation = value; NotifyPropertyChanged("IfpugRepresentation"); }
        }

        public IMeasurable CosmicRepresentation { get; set; }
        
        private UseCasePattern useCasePattern;
        public UseCasePattern UseCasePattern
        {
            get { return useCasePattern; }
            set { useCasePattern = value; NotifyPropertyChanged("UseCasePattern"); }
        }

        private Boolean selectedUseCasePattern;
        public Boolean SelectedUseCasePattern { get { return selectedUseCasePattern; }
            set { selectedUseCasePattern = value; NotifyPropertyChanged("SelectedUseCasePattern"); }
        }

        private UseCaseLayoutCombinations useCaseLayoutCombination;
        public UseCaseLayoutCombinations UseCaseLayoutCombination
        {
            get { return useCaseLayoutCombination; }
            set { useCaseLayoutCombination = value; NotifyPropertyChanged("UseCaseLayout"); }
        }
       
        private Boolean selectedUseCaseLayout;
        public Boolean SelectedUseCaseLayout
        {
            get { return selectedUseCaseLayout; }
            set { selectedUseCaseLayout = value; NotifyPropertyChanged("SelectedUseCaseLayout"); }
        }

        private String typeOfPanel;
        public String TypeOfPanel { get { return typeOfPanel; } set { typeOfPanel = value; NotifyPropertyChanged("typeOfPanel"); } }
            

        public ViewModel()
        {
            App = new Application();
            Time = new Timer(1000);
            Time.Enabled = true;
            Time.Start();
            Time.Elapsed += new System.Timers.ElapsedEventHandler(AddSecond);
            Playing = true;
            Hour = 0;
            Minutes = 0;
            Seconds = 0;
        }

        
        public void AddSecond(object sender, EventArgs e)
        {
            Seconds = Seconds + 1;

            //Agregamos horas en caso de que los minutos sean mas de 60
            if (Minutes >= 60)
            {
                int horasAd = Minutes / 60;
                Hour = Hour + horasAd;
                Minutes = Minutes - horasAd * 60;
            }

            //Agregamos minutos en caso de que los segundos sean mas que 60
            if (Seconds >= 60)
            {
                int minsAdic = Seconds / 60;
                Minutes = Minutes + minsAdic;
                Seconds = Seconds - minsAdic * 60;
            }
        }

        public void PlayPasue() 
        {
            Playing = !Playing;
            if (Playing)
            {
               Time.Start();
            }
            else{
               time.Stop();
            }
     
        }

        public void UpdateIfpug()
        {
            UpdateAppTime();
            IfpugRepresentation = App.ConvertToIfpugModel();
            // Se actualiza la aplicacion
            App.IfpugSize = IfpugRepresentation.Measure();
            NotifyPropertyChanged("App");
        }

        public void UpdateCosmic()
        {
            UpdateAppTime();
            CosmicRepresentation = App.ConvertToCosmicModel();
            // Se actualiza la aplicacion
            App.CosmicSize = CosmicRepresentation.Measure();
            NotifyPropertyChanged("App");
        }

        public void Update()
        {
            UpdateAppTime();
            UpdateIfpug();
            UpdateCosmic();
        }

        public void UpdateAppTime()
        {
            App.Seconds = Seconds;
            App.Minutes = Minutes;
            App.Hours = Hour;
        }

        private void UpdateViewModelTime()
        {
            this.Seconds = App.Seconds;
            this.Minutes = App.Minutes;
            this.Hour = App.Hours;
        }

        internal void Import()
        {
            string fileName = Serializer.Instance.OpenFileDialog();
            if (fileName != null) 
            { 
                App = Serializer.Instance.Deserialize(fileName);
            }
            UpdateViewModelTime();
        }

        internal void ExportHtmlIfpugResult()
        {
            string fileName = Serializer.Instance.SaveHtmlDialog();
            if (fileName != null)
            {
                Serializer.Instance.SaveHTML((IfpugRepresentation as IfpugModel).ToHtml(), fileName);
            }
        }
        internal void ExportCosmicSummary()
        {
            string fileName = Serializer.Instance.SaveHtmlDialog();
            if (fileName != null)
            {
                Serializer.Instance.SaveHTML(( this.CosmicRepresentation as Asistente.Model.COSMIC.CosmicModel).ToHtml(), fileName);
            }
           
        }

        internal void Export()
        {
            UpdateAppTime();
            string fileName = Serializer.Instance.SaveFileDialog();
            if (fileName != null)
            {
                Serializer.Instance.Serialize(App, fileName);
            }
        }

        internal void Export(String fileName)
        {
            if (fileName != null)
            {
                Serializer.Instance.Serialize(App, fileName);
            }
        }

        internal void Reset()
        {
            App = new Application();
            NotifyPropertyChanged("App");
           
        }

        #region New

        internal void NewEntity()
        {
            SelectedEntity = App.NewEntity();
        }

        internal void NewScreen()
        {
            SelectedScreen = SelectedUseCase.NewScreen();
        }

        internal void NewPanel(string type)
        {
            if (type.Equals("Filter"))
                SelectedEditablePanel = SelectedScreen.NewFilter();
            if (type.Equals("Form"))
                SelectedEditablePanel = SelectedScreen.NewForm();
            if (type.Equals("Graph"))
                SelectedReadOnlyPanel = SelectedScreen.NewGraph();
            if (type.Equals("Report"))
                SelectedReadOnlyPanel = SelectedScreen.NewReport();
            if (type.Equals("Grid"))
                SelectedEditablePanel = SelectedScreen.NewGrid();
            NotifyPropertyChanged("App");

        }

        internal void NewUseCase(Entity entity,  UseCasePattern useCasePattern, UseCaseLayoutCombinations useCaseLayoutCombinations=UseCaseLayoutCombinations.SimpleOneOnePanel)
        {
            UseCaseComplexity complexity = UseCaseComplexity.Simple;
            UseCaseLayout layout = UseCaseLayout.OnePanel;
            UseCaseCardinality cardinality = UseCaseCardinality.One;
            switch (useCaseLayoutCombinations)
            {
                case UseCaseLayoutCombinations.ComplexManyOnePanel:
                    complexity = UseCaseComplexity.Complex;
                    cardinality = UseCaseCardinality.Many;
                    layout = UseCaseLayout.OnePanel;
                    break;
                case UseCaseLayoutCombinations.ComplexManyTwoPanel:
                    complexity = UseCaseComplexity.Complex;
                    cardinality = UseCaseCardinality.Many;
                    layout = UseCaseLayout.TwoPanels;
                    break;
                case UseCaseLayoutCombinations.ComplexOneOnePanel:
                    complexity = UseCaseComplexity.Complex;
                    cardinality = UseCaseCardinality.One;
                    layout = UseCaseLayout.OnePanel;
                    break;
                case UseCaseLayoutCombinations.ComplexOneTwoPanel:
                    complexity = UseCaseComplexity.Complex;
                    cardinality = UseCaseCardinality.One;
                    layout = UseCaseLayout.TwoPanels;
                    break;
                case UseCaseLayoutCombinations.SimpleManyOnePanel:
                    complexity = UseCaseComplexity.Simple;
                    cardinality = UseCaseCardinality.Many;
                    layout = UseCaseLayout.OnePanel;
                    break;
                case UseCaseLayoutCombinations.SimpleManyTwoPanel:
                    complexity = UseCaseComplexity.Simple;
                    cardinality = UseCaseCardinality.Many;
                    layout = UseCaseLayout.TwoPanels;
                    break;
                case UseCaseLayoutCombinations.SimpleOneOnePanel:
                    complexity = UseCaseComplexity.Simple;
                    cardinality = UseCaseCardinality.One;
                    layout = UseCaseLayout.OnePanel;
                    break;
                case UseCaseLayoutCombinations.SimpleOneTwoPanel:
                    complexity = UseCaseComplexity.Simple;
                    cardinality = UseCaseCardinality.One;
                    layout = UseCaseLayout.TwoPanels;
                    break;
            }

            SelectedUseCase = App.NewUseCase(useCasePattern, entity, null, complexity, cardinality, layout);

        }

        internal void NewControlReadOnlyPanel()
        {
            SelectedReadOnlyPanel.NewControl();
        }

        internal void NewControlEditablePanel()
        {
            SelectedEditablePanel.NewControl();
        }

        internal void NewUseCaseAction(UseCase useCase)
        {
            SelectedScreen.NewUseCaseAction(useCase);
        }

        internal void NewAction()
        {
            SelectedScreen.NewAction();
        }

        internal void NewMasterDetail()
        {
            SelectedMasterDetail = SelectedScreen.NewMasterDetail();
        }

        internal void NewMaster(String type)
        {
            if (type.Equals("Filter"))
                SelectedEditablePanel = SelectedMasterDetail.NewMasterFilter();
            if (type.Equals("Form"))
                SelectedEditablePanel = SelectedMasterDetail.NewMasterForm();
            if (type.Equals("Grid"))
                SelectedEditablePanel = SelectedMasterDetail.NewMasterGrid();

        }

        internal void NewDetail(String type)
        {
            if (type.Equals("Filter"))
                SelectedEditablePanel = SelectedMasterDetail.NewDetailFilter();
            if (type.Equals("Form"))
                SelectedEditablePanel = SelectedMasterDetail.NewDetailForm();
            if (type.Equals("Grid"))
                SelectedEditablePanel = SelectedMasterDetail.NewMDetailGrid();

        }

        #endregion

        #region Delete

        internal void DeleteEditablePanel()
        {
            App.DeletePanel(SelectedEditablePanel);
        }

        internal void DeleteReadOnlyPanel()
        {
            App.DeletePanel(SelectedReadOnlyPanel);
        }

        internal void DeleteScreen()
        {
            App.DeleteScreen(SelectedScreen);
        }

        internal void DeleteUseCase()
        {
            App.UseCases.Remove(SelectedUseCase);
        }

        internal void DeleteMasterDetail()
        {
            SelectedScreen.DeleteMasterDetail(SelectedMasterDetail);
        }

        internal void DeleteSelectedEntity()
        {
            SelectedEditablePanel.Entity = null;
        }

        internal void DeleteEntity()
        {
            App.DeleteEntity(SelectedEntity);
        }

        #endregion
        
        internal void ChangeUseCase(UseCase uc, UseCasePattern useCasePattern)
        {
            App.ChangeUseCasePattern(uc, useCasePattern);
        }

        internal void CloneUseCase()
        {
            App.CloneUseCase(SelectedUseCase);
        }
        

        /// <summary>
        /// This method check if a particular entity is used in the application
        /// </summary>
        /// <param name="entity">The entity to search in the application</param>
        /// <returns>True if the entity is used in the application</returns>

        public Boolean CanRemoveEntity(Entity entity)
        {
            Boolean flag = true;
            foreach (UseCase useCase in app.UseCases)
            {
                foreach (Screen screen in useCase.Screens)
                {
                    foreach (MasterDetail masterDetails in screen.MasterDetails)
                    {
                        flag=flag & PanelContainsEntity(masterDetails.Master, entity);
                        foreach (EditablePanel panel in masterDetails.Details)
                        {
                           flag=flag  &PanelContainsEntity(panel, entity);
                        }
                    }
                    foreach (Panel panel in screen.Panels)
                    {
                        flag=flag & PanelContainsEntity(panel,entity);
                    }
                }
            }
            return flag;

        }

        /// <summary>
        /// This method check if the panel is related in some way with entity
        /// </summary>
        /// <param name="panel">The panel to check</param>
        /// <param name="entity">The entity to search</param>
        /// <returns>False if the panel is related the entity</returns>
        private Boolean PanelContainsEntity(Panel panel, Entity entity){
            Boolean flag = false;
            String entityName = entity.Name;

            foreach (Control control in panel.Controls)
            {
                if (control.DataGroup != null)
                {
                    Query query = control.DataGroup as Query;
                    foreach (Entity controlEntity in query.UsedEntities)
                    {
                        flag = flag | controlEntity.Name.Equals(entityName);
                    }
                }
            }

            if (typeof(EditablePanel).IsAssignableFrom(panel.GetType()))
            {
                EditablePanel ePanel = panel as EditablePanel;
                if (ePanel.Entity != null)
                {
                    flag = flag | ePanel.Entity.Name.Equals(entityName);
                }

                foreach (Entity upDelCascade in ePanel.UpdatesDeletesCascade)
                {
                    flag = flag | upDelCascade.Name.Equals(entityName);
                } 
            }
            else { 
            ReadOnlyPanel rPanel=panel as ReadOnlyPanel;
            if (rPanel.DataGroup != null)
            {
                Query query = rPanel.DataGroup as Query;
            
                foreach (Entity queryEntity in query.UsedEntities)
                {
                    flag = flag | queryEntity.Name.Equals(entityName);
                }
                } 
            }
            return  !flag ;
        }
    }
}
